package ArithmeticLibrary.Util;

import java.io.ByteArrayOutputStream;
import java.math.BigInteger;

import ArithmeticLibrary.Elements.*;
import ArithmeticLibrary.Sets.*;

import ByteTree.*;

import Cryptographic.HashFunction;
import Cryptographic.PRG;

/**
 * This class performs testing of all the functionality provided in this package, 
 * and class BTConvertor in ByteTree package
 * It has a single main function and different procedures that check functionality
 * 
 * @author Lea Golan
 *
 */
public class Test {

	public static void main(String[] args) throws Exception{
		checkUtil();
		checkBasicGroups();
		checkProduct();
		checkConstructionFromBT();
		testEqualFuncs();
	}

	/**
	 * checks the Util sub package
	 * @throws Exception is any error occurs
	 */
	public static void checkUtil() throws Exception {
		checkPoint();
		checkBigIntegerModulo();
		checkArrayOf();
	}

	/**
	 * checks ProductField and ProductGroup.
	 * @throws Exception if ProductField or ProductGroup throw exception
	 */
	public static void checkProduct() throws Exception {
		checkProductMultGroup();
		checkProductCurveGroup();
		checkProductPrimefield();
	}

	/**
	 * checks PrimeField, EllipticCurve and MultiplicativeGroup 
	 * by creating the sets and elements of the set and using them
	 * @throws Exception if the classes throw any exception
	 */
	public static void checkBasicGroups() throws Exception {
		checkPrimeField();
		checkMultGroup();
		checkEllipticCurve();
	}

	/**
	 * converts different objects from and to ByteTree
	 * @throws Exception if conversion to and from ByteTree fails 
	 */
	public static void checkConstructionFromBT() throws Exception {
		buildMultGroup();
		buildElementPrimeField();
		buildElementMultGroup();
		buildElementEC();
	}

	private static void testEqualFuncs() throws Exception {
		System.out.println("\n\nchecking equal functions\n");
		
		MultiplicativeGroup mult = 
			new MultiplicativeGroup(BigInteger.valueOf(11), 
									BigInteger.valueOf(5), 
									BigInteger.valueOf(4));
		MultiplicativeGroup mult2 = getMultGroup();
		MultiplicativeGroup mult3 = mult;
		
		ElementMultiplicativeGroup elem1 = new ElementMultiplicativeGroup(getRandNum(), mult);
		ElementMultiplicativeGroup elem2 = new ElementMultiplicativeGroup(getRandNum(), mult);
		ElementMultiplicativeGroup elem3 = new ElementMultiplicativeGroup(elem1.getElementValue(), mult);
		ElementMultiplicativeGroup elem4 = new ElementMultiplicativeGroup(getRandNum(), mult2);
				
		System.out.println("check mult groups: expected: false. actual: "+(mult.equals(mult2)));//false
		System.out.println("check mult groups: expected: true. actual: "+(mult.equals(mult3)));//true
		System.out.println("check mult elems: expected: false. actual: "+(elem1.equals(elem2)));//false
		System.out.println("check mult elems: expected: true. actual: "+(elem1.equals(elem3)));//true
		System.out.println("check mult elems: expected: false. actual: "+(elem1.equals(elem4)));//false
		System.out.println();
		
		byte[] curveByte = getByteArrFromStr("secp384r1");
		EllipticCurve curve = 
			new EllipticCurve(new ByteTree(new Leaf(curveByte.length, curveByte)));
		
		byte[] curveByte2 = getByteArrFromStr("secp256r1");
		EllipticCurve curve2 = 
			new EllipticCurve(new ByteTree(new Leaf(curveByte.length, curveByte2)));
		
		HashFunction hash = new HashFunction("SHA-256");
		ElementEllipticCurve[] elem = getCArray(curve.randomArray(5, new PRG(hash), getSeed(), 30));
		ElementEllipticCurve check = elem[2];
		
		System.out.println("check EC groups: expected: false. actual: "+(curve.equals(curve2)));//false
		System.out.println("check EC elems: expected: false. actual: "+(elem[0].equals(elem[1])));//false
		System.out.println("check EC elems: expected: true. actual: "+(elem[2].equals(check)));//true
		
		PrimeField f = new PrimeField(BigInteger.valueOf(821));
		PrimeField f2 = new PrimeField(BigInteger.valueOf(821));
		PrimeField f3 = f;
		PrimeField f4 = new PrimeField(BigInteger.valueOf(911));
		
		ElementPrimeField e1 = new ElementPrimeField(getRandNum(), f);
		ElementPrimeField e2 = new ElementPrimeField(e1.getElementValue(), f2);
		ElementPrimeField e3 = new ElementPrimeField(getRandNum(), f3);
		ElementPrimeField e4 = new ElementPrimeField(getRandNum(), f4);
		
		System.out.println("equals primeField expected true:"+(f.equals(f2)));
		System.out.println("equals primeField expected true:"+(f.equals(f3)));
		System.out.println("equals primeField expected false:"+(f.equals(f4)));
		
		System.out.println("equals primeFieldElem expected true:"+(e1.equals(e2)));
		if (e1.getElementValue() != e3.getElementValue()){
			System.out.println("equals primeFieldElem expected false:"+(e1.equals(e3)));
		}
		System.out.println("equals primeFieldElem expected false:"+(e1.equals(e4)));
		
		System.out.println("\ndone checking equal functions");
	}
	
	private static void buildElementProductField(ElementProductField elem) throws Exception {
		System.out.println("Building ElementProductField from BT: ");
		ByteTree t = getBT(elem);
		
		ElementProductField elemFromBT = new ElementProductField(t, (ProductField)elem.getField());
		for (int i = 0; i < elem.getNumberOfElements(); i++){
			System.out.print("\nExpected: ");
			printElementProductField(elem, "");
			System.out.print("\nActual    ");
			printElementProductField(elemFromBT, "");
		}
		System.out.println("\ndone building ElementProductField from BT\n\n");
	}

	private static ByteTree getBT(ElementField elem) throws Exception {
		ByteArrayOutputStream outStream = new ByteArrayOutputStream();
		
		if(elem instanceof ElementPrimeField){
			ElementPrimeField fieldElement = (ElementPrimeField) elem;
			outStream.write((byte)0x01);
			outStream.write(intToByteArray(fieldElement.getElementValue().toByteArray().length));
			outStream.write(fieldElement.getElementValue().toByteArray());
			return new ByteTree(outStream.toByteArray());			
		}
		
		if (elem instanceof ElementProductField){
			ElementProductField pElem = (ElementProductField) elem;
			outStream.write((byte)0x00);
			outStream.write(intToByteArray(pElem.getNumberOfElements()));
			ByteTree temp;
			for(int i = 0; i < pElem.getNumberOfElements(); i++){
				temp = getBT(pElem.get(i));
				outStream.write(temp.toByteArray());
			}
			return new ByteTree(outStream.toByteArray());
		}
		return null;
	}

	private static void buildBasicArrayOfElementField(ArrayOfElementField arr) throws Exception {
		System.out.println("Building ArrayOfElementProduct from BT:");
		
		ByteTree t = getBasicTree(arr);
		
		ArrayOfElementField arrFromBT = new ArrayOfElementField(t, arr.get(0).getField());
		
		for (int i = 0; i < arr.length(); i++){
			System.out.print("Expected:");
			System.out.print(arr.get(i).getElementValue());
			System.out.print("\tActual:");
			System.out.println(arrFromBT.get(i).getElementValue());
		}
		
		System.out.println("Done Building ArrayOfElementProduct from BT");
	}

	private static ByteTree getBasicTree(ArrayOfElementField arr) throws Exception {
		ByteArrayOutputStream outStream = new ByteArrayOutputStream();
		outStream.write((byte)0x00);
		outStream.write(intToByteArray(arr.length()));
		
		for(int i = 0; i < arr.length(); i++){
			ByteTree temp = getBT(arr.get(i));
			outStream.write(temp.toByteArray());
		}
		
		return new ByteTree(outStream.toByteArray());
	}

	private static void buildProductArrayOfElementField(ArrayOfElementField arr) throws Exception {
		System.out.println("Building complex ArrayOfElementProduct from BT:");
		
		ByteTree t = getProductTree(arr);
		
		ArrayOfElementField arrFromBT = new ArrayOfElementField(t, arr.get(0).getField());
		
		for (int i = 0; i < arr.length(); i++){
			System.out.print("\nExpected:");
			printElementProductField(arr.get(i), "");
			System.out.print("\nActual:  ");
			printElementProductField(arrFromBT.get(i), "");
		}
		
		System.out.println("\nDone Building complex ArrayOfElementProduct from BT");
	}		
	
	
	private static ByteTree getProductTree(
			ArrayOfElementField arr) throws Exception {
		if (arr.length() == 0) return null;
		
		// the ByteTree to be constructed acts like a single productElement 
		//therefore it's number of children is updated accordingly
		int numOfBTChildren = ((ElementProductField)arr.get(0)).getNumberOfElements();
		
		ByteTree temp;
		ByteArrayOutputStream outStream = new ByteArrayOutputStream();
		outStream.write((byte)0x00);
		outStream.write(intToByteArray(numOfBTChildren));
		
		for (int j = 0; j < numOfBTChildren; j++){
			outStream.write(0x00);
			outStream.write(intToByteArray(arr.length()));
			
			for (int i = 0; i < arr.length(); i++){
				temp = getBT(((ElementProductField)arr.get(i)).get(j));
				outStream.write(temp.toByteArray());
			}
		}
		return new ByteTree(outStream.toByteArray());
	}

	private static void buildElementEC() throws Exception {
		System.out.println("Checking: creating elliptic curve group elements from BT");
		
		byte[] curveByte = getByteArrFromStr("secp384r1");
		EllipticCurve curve = 
			new EllipticCurve(new ByteTree(new Leaf(curveByte.length, curveByte)));
		
		HashFunction hash = new HashFunction("SHA-256");
		ElementEllipticCurve[] elem = getCArray(curve.randomArray(5, new PRG(hash), getSeed(), 30));
		ElementEllipticCurve[] elem2 = new ElementEllipticCurve[elem.length];
		
		System.out.print("elements generated from BT: \n[");
		
		ByteTree[] bt = getTrees(elem);
		for (int i = 0; i < elem.length; i++){
			elem2[i] = new ElementEllipticCurve(bt[i], curve);
		}
		
		for (int i = 0; i < elem.length; i++){
			System.out.println("Expected:  "+elem[i].getElementValue()+"\nactual:    "+elem2[i].getElementValue());
		}
		
		BigInteger infinityVal = BigInteger.valueOf(-1);
		
		ByteArrayOutputStream outStream = new ByteArrayOutputStream();
		outStream.write((byte)0x00);
		outStream.write(intToByteArray(2));
		
		outStream.write((byte)0x01);
		outStream.write(intToByteArray(infinityVal.toByteArray().length));
		outStream.write(infinityVal.toByteArray());
		
		outStream.write((byte)0x01);
		outStream.write(intToByteArray(infinityVal.toByteArray().length));
		outStream.write(infinityVal.toByteArray());
		
		ByteTree t= new ByteTree(outStream.toByteArray());
		
		ElementEllipticCurve c = new ElementEllipticCurve(t, curve);
		System.out.println("creating infinity point: ");
		System.out.println(c.getElementValue());
		
		System.out.println("Done checking: creating elliptic curve group elements from BT");
	}

	private static ElementEllipticCurve[] getCArray(
			ArrayOfElementGroup randomArray) throws Exception {
		ElementEllipticCurve[] ret = new ElementEllipticCurve[randomArray.length()];
		for (int i = 0; i < ret.length; i++){
			ret[i] = (ElementEllipticCurve) randomArray.get(i);
		}
		return ret;
	}

	public static byte[] intToByteArray(int x)
	{
		byte[] output = new byte[4];
		output[0] = (byte)(x >> 24);
		output[1] = (byte)(x >> 16);
		output[2] = (byte)(x >> 8);
		output[3] = (byte)(x /*>> 0*/);
		
		return output;
	}
	
	private static ByteTree[] getTrees(ElementEllipticCurve[] elem) throws Exception {
		Point[] vals = new Point[elem.length];
		for (int i = 0; i < elem.length; i++){
			vals[i] = elem[i].getElementValue();
		}
		
		ByteTree[] ret = new ByteTree[elem.length]; 
	
		Leaf xLeaf, yLeaf;
		Node root;
		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		
		for (int i = 0; i < elem.length; i++){			
			xLeaf = new Leaf(vals[i].getX().toByteArray().length, vals[i].getX().toByteArray());
			yLeaf = new Leaf(vals[i].getY().toByteArray().length, vals[i].getY().toByteArray());
			
			stream.write(xLeaf.toByteArray());
			stream.write(yLeaf.toByteArray());
			
			root = new Node(2, stream.toByteArray());
			
			ret[i] = new ByteTree(root);
			stream.reset();
		}
		
		return ret;
	}

	private static void buildElementMultGroup() throws Exception {
		System.out.println("Checking: creating multiplicative group elements from BT");
		
		MultiplicativeGroup p = new MultiplicativeGroup(BigInteger.valueOf(11), BigInteger.valueOf(5), BigInteger.valueOf(4));
		
		byte[] byte3 = {1, 0, 0, 0, 2, 0, (byte) 0x3};
		byte[] byte4 = {1, 0, 0, 0, 2, 0, (byte) 0x4};
		byte[] byte9 = {1, 0, 0, 0, 2, 0, (byte) 0x9};
		
		ElementMultiplicativeGroup elem3 = new ElementMultiplicativeGroup(new ByteTree(byte3), p);
		ElementMultiplicativeGroup elem4 = new ElementMultiplicativeGroup(new ByteTree(byte4), p);
		ElementMultiplicativeGroup elem9 = new ElementMultiplicativeGroup(new ByteTree(byte9), p);
		
		System.out.println("expected 3\t actual: "+elem3.getElementValue());
		System.out.println("expected 4\t actual: "+elem4.getElementValue());
		System.out.println("expected 9\t actual: "+elem9.getElementValue());
		
		System.out.println("Done checking: creating multiplicative group elements from BT\n\n");
	}

	private static void buildElementPrimeField() throws Exception {
		System.out.println("Checking: creating prime field elements from BT");
		
		PrimeField p = new PrimeField(BigInteger.valueOf(263));
		byte[] byte132 = {1, 0, 0, 0, 2, 0, (byte) 0x84};
		byte[] byte145 = {1, 0, 0, 0, 2, 0, (byte) 0x91};
		byte[] byte94 =  {1, 0, 0, 0, 2, 0, (byte) 0x5E};
		
		ElementPrimeField elem132 = new ElementPrimeField(new ByteTree(byte132), p);
		ElementPrimeField elem145 = new ElementPrimeField(new ByteTree(byte145), p);
		ElementPrimeField elem94 = new ElementPrimeField(new ByteTree(byte94), p);
		
		System.out.println("expected 132\t actual: "+elem132.getElementValue());
		System.out.println("expected 145\t actual: "+elem145.getElementValue());
		System.out.println("expected 94 \t actual: "+elem94.getElementValue());
		
		System.out.println("Done checking: creating prime field elements from BT\n\n");
	}
	
	private static byte[] hexStringToByteArray(String s) throws Exception {
		    int len = s.length();
		    if ((len % 2) != 0)
		    	throw new Exception("seed length must be even");
		    byte[] data = new byte[len / 2];
		    for (int i = 0; i < len; i += 2) {
		        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
		                             + Character.digit(s.charAt(i+1), 16));
		    }
		    return data;
		}
	
	private static MultiplicativeGroup getMultGroup() throws Exception{
		String s = 	"00000000040100000041014354c848a190b7b5fbddcd07bed36e59af5a50cc5966b"+
		"202bba0959ccc42061a2f468f87fa436451bd48d5cb333c0bb0aca763193e70c725495455"+
		"a99939276f010000004100a1aa642450c85bdafdeee683df69b72cd7ad28662cb359015dd"+
		"04ace6621030d17a347c3fd21b228dea46ae5999e05d85653b18c9f386392a4aa2ad4cc9c"+
		"93b701000000410132027413c1464af9b3ebe05f40059902857843365887f3e084e973dfd"+
		"3da198697724ac422dfce4728c2baa07760b5eae2d709bd7ff4f79d4e71fc9c2d37e26701"+
		"0000000400000001"; 
		
		byte[] sBytes = hexStringToByteArray(s);
		ByteTree BT = new ByteTree(sBytes);
		return new MultiplicativeGroup(BT);
	}

	private static void buildMultGroup() throws Exception {
		System.out.println("checking Creation of MultGroup from BT:");
		
		MultiplicativeGroup mult = getMultGroup();
		
		System.out.println("group params:");
		System.out.println("q "+mult.getGroupOrder()+"\np "+mult.getSuperGroupOrder());
		System.out.println("unit element:\t"+mult.getGroupIdentityElement().getElementValue());
		System.out.println("generator:\t"+mult.getGroupGenerator().getElementValue());
		
		HashFunction hash = new HashFunction("SHA-256");;
		
		ElementMultiplicativeGroup[] randArr = getMArray(mult.randomArray(5, new PRG(hash), getSeed(), 30)); 
		System.out.print("random elems:\t[");
		for (int i = 0; i < randArr.length-1; i++){
			System.out.print(randArr[i].getElementValue()+", ");
		}
		System.out.println(randArr[randArr.length-1].getElementValue()+"]");
		
		System.out.println("done checking Creation of MultGroup from BT\n\n");
	}

	private static ElementMultiplicativeGroup[] getMArray(
			ArrayOfElementGroup randomArray) throws Exception {
		ElementMultiplicativeGroup[] ret = new ElementMultiplicativeGroup[randomArray.length()];
		for (int i = 0; i < ret.length; i++){
			ret[i] = (ElementMultiplicativeGroup) randomArray.get(i);
		}
		return ret;
	}

	private static void checkProductCurveGroup() throws Exception {
		System.out.println("checking ProductCurveGroup:");
		
		EllipticCurve curveArr1 = new EllipticCurve(new ByteTree(new Leaf(0, getByteArrFromStr("secp224r1"))));
		EllipticCurve curveArr2 = new EllipticCurve(new ByteTree(new Leaf(0, getByteArrFromStr("P-521"))));
		EllipticCurve curveArr3 = new EllipticCurve(new ByteTree(new Leaf(0, getByteArrFromStr("brainpoolp320r1"))));	
		
		ElementEllipticCurve[] elem1 = getCArray(curveArr1.randomArray(4, new PRG(new HashFunction("SHA-256")), getSeed(), 10));
		ElementEllipticCurve[] elem2 = getCArray(curveArr2.randomArray(4, new PRG(new HashFunction("SHA-256")), getSeed(), 30));
		ElementEllipticCurve[] elem3 = getCArray(curveArr3.randomArray(4, new PRG(new HashFunction("SHA-256")), getSeed(), 20));
		
		EllipticCurve[] arr1 = {curveArr1, curveArr2, curveArr3};
		EllipticCurve[] arr2 = {curveArr1, curveArr3};
		EllipticCurve[] arr3 = {curveArr2, curveArr3};
		
		ElementEllipticCurve[] arr1elem = {elem1[0], elem2[0], elem3[0]};
		ElementEllipticCurve[] arr2elem = {elem1[1], elem3[1]};
		ElementEllipticCurve[] arr3elem = {elem2[1], elem3[2]};
		
		ProductGroup[] productArr = new ProductGroup[3];
		ElementProductGroup[] elemProduct = new ElementProductGroup[3];
		
		productArr[0] = new ProductGroup(arr1);
		productArr[1] = new ProductGroup(arr2);
		productArr[2] = new ProductGroup(arr3);
		
		elemProduct[0] = new ElementProductGroup(arr1elem, productArr[0]);
		elemProduct[1] = new ElementProductGroup(arr2elem, productArr[1]);
		elemProduct[2] = new ElementProductGroup(arr3elem, productArr[2]);
		
		Group[] mix1 = {curveArr1, curveArr1};
		Group[] mix2 = {productArr[0], curveArr2, productArr[1]};
		Group[] mix3 = {productArr[2], mix2[0], mix2[1], mix2[2]};
		
		ElementGroup[] elemMix1 = {elem1[2], null};
		ElementGroup[] elemMix2 = {elemProduct[0], elem2[1], elemProduct[1]};
		ElementGroup[] elemMix3 = {elemProduct[2], elemProduct[0], elem2[2], elemProduct[1]};
		
		ProductGroup test1 = new ProductGroup(mix1);
		ProductGroup test1C = new ProductGroup(mix1);
		ProductGroup test2 = new ProductGroup(mix2);
		ProductGroup test3 = new ProductGroup(mix3);
			
		ElementProductGroup elemTest1 = new ElementProductGroup(elemMix1, test1);
		ElementProductGroup elemTest2 = new ElementProductGroup(elemMix2, test2);
		ElementProductGroup elemTest3 = new ElementProductGroup(elemMix3, test3);
			
		System.out.println("mult: ");
		printElementProductGroup(elemTest1,"");
		System.out.println("*");
		printElementProductGroup(elemTest1,"");
		System.out.println("=");
		printElementProductGroup(elemTest1.multiply(elemTest1), "");
		System.out.println("\npower: ");
		printElementProductGroup(elemTest1,"");
		System.out.println("\n^56=");
		printElementProductGroup(elemTest1.power(BigInteger.valueOf(56)), "");
		System.out.println("\nmultInverse of");
		printElementProductGroup(elemTest1, "");
		System.out.print("\n is");
		printElementProductGroup(elemTest1.multInverse(), "");
		System.out.println("\ndivide: ");
		printElementProductGroup(elemTest1,"");
		System.out.println("/");
		printElementProductGroup(elemTest1,"");
		System.out.println("=");
		printElementProductGroup(elemTest1.divide(elemTest1), "");
		
		System.out.println("\nequals PGroup excpected true:"+test1.equals(test1C));
		System.out.println("equals PGroup excpected false:"+test1.equals(test2));
		System.out.println("equals PGroup excpected false:"+elemTest1.equals(elemTest2));
		
		System.out.print("\nmult: ");
		printElementProductGroup(elemTest2.multiply(elemTest2), "");
		System.out.println("\ninverse: ");
		printElementProductGroup(elemTest3.multInverse(), "");
		
		System.out.println("\nconverting from and to BT:");
		
		System.out.println("\nExcpected:");
		printElementProductGroup(elemTest2, "");
		ByteTree temp2 = BTconvertor.convertElementProductGroupToBT(elemTest2);
		ElementProductGroup elemTest2FromBT = new ElementProductGroup(temp2, test2);
		System.out.println("\nActual:");
		printElementProductGroup(elemTest2FromBT, "");
		
		System.out.println("\nExcpected:");
		printElementProductGroup(elemTest3, "");
		ByteTree temp3 = BTconvertor.convertElementProductGroupToBT(elemTest3);
		ElementProductGroup elemTest3FromBT = new ElementProductGroup(temp3, test3);
		System.out.println("\nActual:");
		printElementProductGroup(elemTest3FromBT, "");
		
		System.out.println("\ndone checking ProductGroup\n\n");
	}

	private static void checkProductMultGroup() throws Exception {
		System.out.println("checking ProductMultGroup:");
		
		MultiplicativeGroup[] arr = new MultiplicativeGroup[2];
		arr[0] = new MultiplicativeGroup(BigInteger.valueOf(11), 
					BigInteger.valueOf(5), BigInteger.valueOf(4));
		arr[1] = getMultGroup();	
		
		ArrayOfElementGroup elem1 = arr[0].randomArray(4, new PRG(new HashFunction("SHA-256")), getSeed(), 10);
		ArrayOfElementGroup elem2 = arr[1].randomArray(4, new PRG(new HashFunction("SHA-256")), getSeed(), 30);
		
		ProductGroup p = new ProductGroup(arr);
		
		
		ElementGroup[] ret = {elem1.get(2), elem2.get(1)};
		ElementProductGroup elemTest1 = new ElementProductGroup(ret, p);		
			
		System.out.println("mult: ");
		printElementProductGroup(elemTest1,"");
		System.out.println("*");
		printElementProductGroup(elemTest1,"");
		System.out.println("=");
		printElementProductGroup(elemTest1.multiply(elemTest1), "");
		System.out.println("\npower: ");
		printElementProductGroup(elemTest1,"");
		System.out.println("\n^56=");
		printElementProductGroup(elemTest1.power(BigInteger.valueOf(56)), "");
		System.out.println("\nmultInverse of");
		printElementProductGroup(elemTest1, "");
		System.out.print("\n is");
		printElementProductGroup(elemTest1.multInverse(), "");
		System.out.println("\ndivide: ");
		printElementProductGroup(elemTest1,"");
		System.out.println("/");
		printElementProductGroup(elemTest1,"");
		System.out.println("=");
		printElementProductGroup(elemTest1.divide(elemTest1), "");
		
		System.out.println("\ndone checking ProductGroup\n\n");
	}
	
	private static void printElementProductGroup(ElementGroup elem, String hazaha) throws Exception {
		if (elem == null){
			System.out.print(hazaha+"null");
			return;
		}
		if (elem instanceof ElementEllipticCurve){
			System.out.print(hazaha+((ElementEllipticCurve) elem).getElementValue());
			return;
		}
		if (elem instanceof ElementMultiplicativeGroup){
			System.out.print(hazaha+((ElementMultiplicativeGroup) elem).getElementValue());
			return;
		}
		if (elem instanceof ElementProductGroup){
			ElementProductGroup e = (ElementProductGroup) elem;
			for (int i = 0; i < e.getNumberOfElements(); i++){
				printElementProductGroup(e.get(i), hazaha+" ");
			}
		}
		else {
			throw new Exception("something is wrong");
		}
	}

	private static void printElementProductField(ElementField elem, String hazaha) throws Exception {
		if (elem == null){
			System.out.print(hazaha+"null");
			return;
		}
		if (elem instanceof ElementPrimeField){
			System.out.print(hazaha+((ElementPrimeField) elem).getElementValue());
			return;
		}
		if (elem instanceof ElementProductField){
			ElementProductField e = (ElementProductField) elem;
			for (int i = 0; i < e.getNumberOfElements(); i++){
				printElementProductField(e.get(i), hazaha+" ");
			}
		}
		else {
			throw new Exception("something is wrong");
		}
	}
	
	private static void checkProductPrimefield() throws Exception {
		System.out.println("checking ProductField:"); 
		
		PrimeField[] primeFieldArr1 = initPrimeField(1);
		PrimeField[] primeFieldArr2 = initPrimeField(2);
		PrimeField[] primeFieldArr3 = initPrimeField(3);		
		
		ElementField[] elem1 = initFieldElems(1, primeFieldArr1);
		ElementField[] elem2 = initFieldElems(2, primeFieldArr2);
		ElementField[] elem3 = initFieldElems(3, primeFieldArr3);
		
		ProductField[] productArr = new ProductField[3];
		ElementProductField[] elemProduct = new ElementProductField[3];
		
		productArr[0] = new ProductField(primeFieldArr1);
		productArr[1] = new ProductField(primeFieldArr2);
		productArr[2] = new ProductField(primeFieldArr3);
		
		elemProduct[0] = new ElementProductField(elem1, productArr[0]);
		elemProduct[1] = new ElementProductField(elem2, productArr[1]);
		elemProduct[2] = new ElementProductField(elem3, productArr[2]);
		
		Field[] mix1 = {primeFieldArr1[0], primeFieldArr1[0]};
		Field[] mix2 = {productArr[2], primeFieldArr1[1], productArr[1]};
		Field[] mix3 = {productArr[2], mix2[0], mix2[1], mix2[2]};
		
		ElementField[] elemMix1 = {elemProduct[0].get(0), null};
		ElementField[] elemMix2 = {elemProduct[2], elemProduct[1].get(1), elemProduct[1]};
		ElementField[] elemMix3 = {elemProduct[2], elemProduct[2], /*elem1[1]*/elemProduct[1].get(1), elemProduct[1]};
		
		ProductField test1 = new ProductField(mix1);
		ProductField test1c = new ProductField(mix1);
		ProductField test2 = new ProductField(mix2);
		ProductField test3 = new ProductField(mix3);
			
		ElementProductField elemTest1 = new ElementProductField(elemMix1, test1);
		ElementProductField elemTest2 = new ElementProductField(elemMix2, test2);
		ElementProductField elemTest3 = new ElementProductField(elemMix3, test3);
		
		System.out.println("equals prodField expected false:"+test1.equals(test2));
		System.out.println("equals prodField expected true:"+test1.equals(test1c));
		System.out.println("equals elems excpected false:"+elemMix1.equals(elemMix3));
		System.out.println("equals elems excpected true:"+elemMix2[0].equals(elemMix3[0]));
		System.out.println();
		
		System.out.println("add: ");
		printElementProductField(elemTest1,"");
		System.out.println("+");
		printElementProductField(elemTest1,"");
		System.out.println("=");
		printElementProductField(elemTest1.multiply(elemTest1), "");
		System.out.println("\nmult: ");
		printElementProductField(elemTest1,"");
		System.out.println("*");
		printElementProductField(elemTest1,"");
		System.out.println("=");
		printElementProductField(elemTest1.multiply(elemTest1), "");
		System.out.println("\npower: ");
		printElementProductField(elemTest2,"");
		System.out.println("\n^56=");
		printElementProductField(elemTest2.power(BigInteger.valueOf(56)), "");
		System.out.println("\nmultInverse of");
		printElementProductField(elemTest3, "");
		System.out.print("\n is");
		printElementProductField(elemTest3.multInverse(), "");
		System.out.println("\naddInverse of");
		printElementProductField(elemTest2, "");
		System.out.print("\n is");
		printElementProductField(elemTest2.additiveInverse(), "");
		
		System.out.println("\ndone checking ProductField\n\n");
	
		buildElementProductField(elemTest2);
		buildElementProductField(elemTest3);
	}

	private static ElementField[] initFieldElems(int i, PrimeField[] arrField) {
		ElementPrimeField[] arr = new ElementPrimeField[5];
		if (i==1){
			arr[0] = new ElementPrimeField(BigInteger.valueOf(24), arrField[0]);
			arr[1] = new ElementPrimeField(BigInteger.valueOf(453), arrField[1]);
			arr[2] = new ElementPrimeField(BigInteger.valueOf(44), arrField[2]);
			arr[3] = new ElementPrimeField(BigInteger.valueOf(732), arrField[3]);
			arr[4] = new ElementPrimeField(BigInteger.valueOf(757), arrField[4]);
			return arr;
		}
		if(i == 2){
			arr[0] = new ElementPrimeField(BigInteger.valueOf(24537), arrField[0]);
			arr[1] = new ElementPrimeField(BigInteger.valueOf(1), arrField[1]);
			arr[2] = new ElementPrimeField(BigInteger.valueOf(1), arrField[2]);
			arr[3] = new ElementPrimeField(BigInteger.valueOf(37), arrField[3]);
			arr[4] = new ElementPrimeField(BigInteger.valueOf(3200), arrField[4]);
			return arr;
		}
		if (i == 3){
			arr[0] = new ElementPrimeField(BigInteger.valueOf(422537), arrField[0]);
			arr[1] = new ElementPrimeField(BigInteger.valueOf(55), arrField[1]);
			arr[2] = new ElementPrimeField(BigInteger.valueOf(5396), arrField[2]);
			arr[3] = new ElementPrimeField(BigInteger.valueOf(10), arrField[3]);
			arr[4] = new ElementPrimeField(BigInteger.valueOf(5967), arrField[4]);
			return arr;
		}
		return null;
	}

	private static PrimeField[] initPrimeField(int i) throws Exception {
		PrimeField[] primeArr = new PrimeField[5];
		if (i==1){
			primeArr[0] = new PrimeField(BigInteger.valueOf(11));
			primeArr[1] = new PrimeField(BigInteger.valueOf(163));
			primeArr[2] = new PrimeField(BigInteger.valueOf(59));
			primeArr[3] = new PrimeField(BigInteger.valueOf(67));
			primeArr[4] = new PrimeField(BigInteger.valueOf(31));
			return primeArr;
		}
		if (i==2){
			primeArr[0] = new PrimeField(BigInteger.valueOf(5));
			primeArr[1] = new PrimeField(BigInteger.valueOf(61));
			primeArr[2] = new PrimeField(BigInteger.valueOf(37));
			primeArr[3] = new PrimeField(BigInteger.valueOf(47));
			primeArr[4] = new PrimeField(BigInteger.valueOf(29));
			return primeArr;
		}
		if (i==3){
			primeArr[0] = new PrimeField(BigInteger.valueOf(19));
			primeArr[1] = new PrimeField(BigInteger.valueOf(17));
			primeArr[2] = new PrimeField(BigInteger.valueOf(97));
			primeArr[3] = new PrimeField(BigInteger.valueOf(41));
			primeArr[4] = new PrimeField(BigInteger.valueOf(83));
			return primeArr;
		}
		return null;
	}

	private static void checkEllipticCurve() throws Exception {
		System.out.println("Checking EllipticCurve");
		
		byte[] curveByte = getByteArrFromStr("secp192k1");
		EllipticCurve curve = 
			new EllipticCurve(new ByteTree(new Leaf(curveByte.length, curveByte)));
	
		HashFunction hash = new HashFunction("SHA-256");;
		
		ElementEllipticCurve[] elems = getCArray(curve.randomArray(10, new PRG(hash), getSeed(), 0));
		
		System.out.print("random generated elements:\n[");
		for (int i = 0; i < elems.length-1; i++){
			System.out.println(elems[i].getElementValue()+", ");
		}
		System.out.println(elems[elems.length-1].getElementValue()+"]");
		
		System.out.println("mulyiply\n"+elems[1].getElementValue()+"*\n"+elems[2].getElementValue()+"=\n"+elems[1].multiply(elems[2]).getElementValue());
		BigInteger temp = getRandNum();
		System.out.println("power\n"+elems[3].getElementValue()+"^\n"+temp+"=\n"+elems[3].power(temp).getElementValue());
		System.out.println("element value before change: "+elems[4].getElementValue());
		try {
			elems[4].setElementValue(new Point(getRandNum(), getRandNum()));
		} catch (Exception e) {
			System.out.println("Exception thrown correctly");
		}
		System.out.println("after change: "+elems[4].getElementValue());
		System.out.println("divide:\n"+elems[5].getElementValue()+"/\n"+elems[6].getElementValue()+"=\n"+elems[5].divide(elems[6]).getElementValue());
		System.out.println("multInverse of \n"+elems[7].getElementValue()+"\nis "+elems[7].multInverse().getElementValue());
		System.out.println("unitElement:\t"+curve.getGroupIdentityElement().getElementValue());
		System.out.println("generator:\t"+curve.getGroupGenerator().getElementValue());

		System.out.println("done checking EllipticCurve\n\n");		
	}

	private static byte[] getByteArrFromStr(String string) {
		byte[] ret = new byte[string.length()];
		
		for (int i = 0; i < string.length(); i++){
			ret[i] = (byte) string.charAt(i);
		}
		return ret;
	}

	private static void checkMultGroup() throws Exception {
		System.out.println("Checking MultiplicativeGroup");
				
		MultiplicativeGroup mult = 
			new MultiplicativeGroup(BigInteger.valueOf(11), 
									BigInteger.valueOf(5), 
									BigInteger.valueOf(4));
		
		ElementMultiplicativeGroup elem1 = new ElementMultiplicativeGroup(getRandNum(), mult);
		ElementMultiplicativeGroup elem2 = new ElementMultiplicativeGroup(getRandNum(), mult);
		ElementMultiplicativeGroup elem3 = new ElementMultiplicativeGroup(getRandNum(), mult);
		ElementMultiplicativeGroup elem4 = new ElementMultiplicativeGroup(getRandNum(), mult);
		ElementMultiplicativeGroup elem5 = new ElementMultiplicativeGroup(getRandNum(), mult);
		
		
		System.out.println("mult:\t"+elem1.getElementValue()+"*"+elem2.getElementValue()+"="+elem1.multiply(elem2).getElementValue());
		System.out.println("power:\t"+elem3.getElementValue()+"^"+elem4.getElementValue()+"="+elem3.power(elem4.getElementValue()).getElementValue());
		try {
			System.out.println("divide:\t"+elem4.getElementValue()+"/"+elem5.getElementValue()+"="+elem4.divide(elem5).getElementValue());
		} catch (Exception e1) {
			if (elem5.getElementValue().signum() != 0) throw e1;
			else System.out.println("Exception thrown correctly for dividing by zero");
		}
		System.out.print("element before change: "+elem1.getElementValue());
		elem1.setElementValue(getRandNum());
		System.out.println(" after change: "+elem1.getElementValue());
		System.out.println("unit element:\t"+mult.getGroupIdentityElement().getElementValue());
		System.out.println("generator:\t"+mult.getGroupGenerator().getElementValue());
		System.out.println("params: q "+mult.getGroupOrder()+" p "+mult.getSuperGroupOrder());
		try {
			System.out.println("multInverse:\t"+elem3.multInverse().getElementValue());
		} catch (Exception e1) {
			if (elem3.getElementValue().signum() != 0) throw e1;
			else System.out.println("Exception thrown correctly for dividing by zero");
		}
		
		HashFunction hash = new HashFunction("SHA-256");;
		
		ElementMultiplicativeGroup[] randArr = getMArray(mult.randomArray(5, new PRG(hash), getSeed(), 30)); 
		System.out.print("random elems:\t[");
		for (int i = 0; i < randArr.length-1; i++){
			System.out.print(randArr[i].getElementValue()+", ");
		}
		System.out.println(randArr[randArr.length-1].getElementValue()+"]");
		
		System.out.println("Done checking MultiplicativeGroup\n\n");
	}

	private static byte[] getSeed() {
		String s = "62779017353866899638357894232076";
		byte[] ret = getByteArrFromStr(s);
		return ret;
	}

	private static void checkPrimeField() throws Exception {
		System.out.println("Checking PrimeField");
		
		PrimeField prime = new PrimeField(BigInteger.valueOf(739));
		
		ElementPrimeField elem1 = new ElementPrimeField(getRandNum(), prime);
		ElementPrimeField elem2 = new ElementPrimeField(getRandNum(), prime);
		ElementPrimeField elem3 = new ElementPrimeField(getRandNum(), prime);
		ElementPrimeField elem4 = new ElementPrimeField(getRandNum(), prime);
		ElementPrimeField elem5 = new ElementPrimeField(getRandNum(), prime);
		ElementPrimeField elem6 = new ElementPrimeField(BigInteger.valueOf(56), prime);
		
		System.out.println("add:\t"+elem1.getElementValue()+"+"+elem2.getElementValue()+"="+elem1.add(elem2).getElementValue());
		System.out.println("multiply: "+elem3.getElementValue()+"+"+elem4.getElementValue()+"="+elem3.multiply(elem4).getElementValue());
		System.out.println("power:\t"+elem5.getElementValue()+"^50="+elem5.power(new BigInteger("50")).getElementValue());
		elem6.setElementValue(getRandNum());
		System.out.println("element old value: "+56+" new value: "+elem6.getElementValue());
		System.out.println("unitElement:\t"+prime.getFieldIdentityElement().getElementValue());
		System.out.println("addInverse of "+elem5.getElementValue()+" is "+elem5.additiveInverse().getElementValue());
		System.out.println("multInvrse of "+elem5.getElementValue()+" is "+elem2.multInverse().getElementValue());
		
		System.out.println("Done checking PrimeField\n\n");
	}

	private static void checkArrayOf() throws Exception {
		checkArrayOfElementField();
		checkArrayOfElementMultGroup();
		checkArrayOfElementEllipticCurve1();
		checkArrayOfElementEllipticCurve2();
	}
	
	private static void checkArrayOfElementEllipticCurve1() throws Exception {
		System.out.println("checking ArrayOfElement for elliptic curves");
		
		EllipticCurve[] arr = new EllipticCurve[2];

		arr[0] = new EllipticCurve(new ByteTree(new Leaf(0, getByteArrFromStr("brainpoolp256r1"))));
		arr[1] = new EllipticCurve(new ByteTree(new Leaf(0, getByteArrFromStr("prime239v1"))));
		
		ProductGroup p = new ProductGroup(arr);
		
		ArrayOfElementGroup elems0 = arr[0].randomArray(10, new PRG(new HashFunction("SHA-256")), getSeed(), 20);
		ArrayOfElementGroup elems1 = arr[1].randomArray(10, new PRG(new HashFunction("SHA-256")), getSeed(), 20);
		
		System.out.println("Checking basic array of elliptic curve elements");
		
		System.out.println("[");
		for (int i = 0; i < elems0.length(); i++){
			System.out.println(((ElementEllipticCurve) elems0.get(i)).getElementValue());
		}
		System.out.println("]\n[");
		for (int i = 0; i < elems1.length(); i++){
			System.out.println(((ElementEllipticCurve) elems1.get(i)).getElementValue());
		}

		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		ByteTree temp;
		
		stream.write(0x00);
		stream.write(intToByteArray(2));
		
		stream.write(0x00);
		stream.write(intToByteArray(2));
		
		temp = BTconvertor.convertElementGroupToBT(elems0.get(2));
		stream.write(temp.toByteArray());
		temp = BTconvertor.convertElementGroupToBT(elems0.get(3));
		stream.write(temp.toByteArray());
		
		stream.write(0x00);
		stream.write(intToByteArray(2));
		
		temp = BTconvertor.convertElementGroupToBT(elems1.get(9));
		stream.write(temp.toByteArray());
		temp = BTconvertor.convertElementGroupToBT(elems1.get(7));
		stream.write(temp.toByteArray());
			
		ByteTree test = new ByteTree(stream.toByteArray());
		
		ArrayOfElementGroup ellipticTest = new ArrayOfElementGroup(test, p);
		
		System.out.println("checking product array of ellipticCurve:");
		
		System.out.print("[");
		for (int i = 0; i < ellipticTest.length(); i++){
			printElementProductGroup(ellipticTest.get(i), "");
			System.out.println();
		}
		System.out.println("]\n");
	
		System.out.println("done checking ArrayOfElement for elliptic curves\n\n");
	}

	private static void checkArrayOfElementEllipticCurve2() throws Exception {
		System.out.println("checking ArrayOfElement for elliptic curves");
		
		EllipticCurve[] arr1 = new EllipticCurve[1];
		EllipticCurve[] arr2 = new EllipticCurve[1];
		
		arr1[0] = new EllipticCurve(new ByteTree(new Leaf(0, getByteArrFromStr("brainpoolp256r1"))));
		arr2[0] = new EllipticCurve(new ByteTree(new Leaf(0, getByteArrFromStr("prime239v1"))));
		
		ProductGroup p1 = new ProductGroup(arr1);
		ProductGroup p2 = new ProductGroup(arr2);
		
		ProductGroup[] arr = {p1, p2};
		
		ProductGroup p = new ProductGroup(arr);
		
		ArrayOfElementGroup elems0 = arr1[0].randomArray(10, new PRG(new HashFunction("SHA-256")), getSeed(), 20);
		ArrayOfElementGroup elems1 = arr2[0].randomArray(10, new PRG(new HashFunction("SHA-256")), getSeed(), 20);
		
		System.out.println("Checking basic array of elliptic curve elements");
		
		System.out.println("[");
		for (int i = 0; i < elems0.length(); i++){
			System.out.println(((ElementEllipticCurve) elems0.get(i)).getElementValue());
		}
		System.out.println("]\n[");
		for (int i = 0; i < elems1.length(); i++){
			System.out.println(((ElementEllipticCurve) elems1.get(i)).getElementValue());
		}

		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		ByteTree temp;
		
		stream.write(0x00);
		stream.write(intToByteArray(2));
		
		stream.write(0x00);
		stream.write(intToByteArray(2));
		
		temp = BTconvertor.convertElementGroupToBT(elems0.get(2));
		stream.write(temp.toByteArray());
		temp = BTconvertor.convertElementGroupToBT(elems0.get(3));
		stream.write(temp.toByteArray());
		
		stream.write(0x00);
		stream.write(intToByteArray(2));
		
		temp = BTconvertor.convertElementGroupToBT(elems1.get(9));
		stream.write(temp.toByteArray());
		temp = BTconvertor.convertElementGroupToBT(elems1.get(7));
		stream.write(temp.toByteArray());
			
		ByteTree test = new ByteTree(stream.toByteArray());
		
		ArrayOfElementGroup ellipticTest = new ArrayOfElementGroup(test, p);
		
		System.out.println("checking product array of ellipticCurve:");
		
		System.out.print("[");
		for (int i = 0; i < ellipticTest.length(); i++){
			printElementProductGroup(ellipticTest.get(i), "");
			System.out.println();
		}
		System.out.println("]\n");
	
		System.out.println("done checking ArrayOfElement for elliptic curves\n\n");
	}
	
	private static void checkArrayOfElementMultGroup() throws Exception {
		System.out.println("Checking ArrayOfElementGroup");
		
		System.out.println("\nchecking basic array:");
		
		MultiplicativeGroup group = 
			new MultiplicativeGroup(BigInteger.valueOf(11), BigInteger.valueOf(5), BigInteger.valueOf(4));
		
		ArrayOfElementGroup arr = 
				new ArrayOfElementGroup(10, group);
		
		for (int i = 0; i < arr.getMaxSize(); i++){
			arr.set(i, new ElementMultiplicativeGroup(getRandNum(), group));
		}
		
		System.out.print("[");
		for (int i = 0; i < arr.getMaxSize()-1; i++){
			System.out.print(((ElementMultiplicativeGroup) arr.get(i)).getElementValue()+", ");
		}
		System.out.println(
			((ElementMultiplicativeGroup) arr.get(arr.getMaxSize()-1)).getElementValue()+"]");
		
		try {
			arr.set(10, new ElementMultiplicativeGroup(BigInteger.valueOf(12557), group));
		} catch (Exception e) {
			System.out.println("Exception thrown correctly");
		}
		
		System.out.println("\nchecking product array of group elements:");
		
		MultiplicativeGroup[] multGroups = new MultiplicativeGroup[2]; 
		multGroups[0] = group;
		multGroups[1] = getMultGroup();
		
		ElementGroup[] elemsGroups = new ElementGroup[10];
		for (int i = 0; i < 5; i++){
			elemsGroups[i] = new ElementMultiplicativeGroup(getRandNum(), multGroups[0]);
		}
		for (int i = 5; i < 10; i++){
			elemsGroups[i] = new ElementMultiplicativeGroup(getRandNum(), multGroups[1]);
		}
		
		ProductGroup pgroup = new ProductGroup(multGroups);
		
		ElementProductGroup[] pelems = new ElementProductGroup[5];
		for (int i = 0; i < pelems.length; i++){
			pelems[i] = new ElementProductGroup(pgroup);
			pelems[i].set(0, elemsGroups[i]);
			pelems[i].set(1, elemsGroups[i+5]);
		}
		
		ArrayOfElementGroup parr = 
				new ArrayOfElementGroup(5, pgroup);
		ArrayOfElementGroup parrc = 
			new ArrayOfElementGroup(5, pgroup);
		
		for (int i = 0; i < parr.getMaxSize(); i++){
			parr.set(i, pelems[i]);
			parrc.set(i, pelems[i]);
		}
		
		System.out.print("[");
		for (int i = 0; i < parr.getMaxSize(); i++){
			printElementProductGroup(parr.get(i), "");
		}
		System.out.println("]");
		
		try {
			parr.set(10, new ElementProductGroup(pgroup));
		} catch (Exception e) {
			System.out.println("Exception thrown correctly");
		}
		
		System.out.println("equals arrGroup expected true:"+(parrc.equals(parr)));
		System.out.println("equals arrGroup expected false:"+(parrc.equals(arr)));
		System.out.println("equals arrGroup expected false:"+(parrc.get(0).equals(arr)));
		System.out.println("equals arrGroup expected true:"+(parrc.equals(parrc)));
		System.out.println("equals arrGroup expected true:"+(arr.equals(arr)));
		
		System.out.println("converting from and to BT:");
		
		ByteTree temp = BTconvertor.convertArrayOfElementGroupToBT(arr);

		ArrayOfElementGroup arrFromBT = new ArrayOfElementGroup(temp, group);
		
		System.out.println("arr from BT:");
		System.out.print("[");
		for (int i = 0; i < arrFromBT.getMaxSize(); i++){
			System.out.print("[");
			printElementProductGroup(arrFromBT.get(i), "");
			System.out.print("]");
		}
		System.out.println("]");
		
		temp = BTconvertor.convertArrayOfProductGroupToBT(parr);
		
		ArrayOfElementGroup parrFromBT = new ArrayOfElementGroup(temp, pgroup);
		System.out.println("parr from BT:");
		System.out.print("[");
		for (int i = 0; i < parrFromBT.getMaxSize(); i++){
			System.out.print("[");
			printElementProductGroup(parrFromBT.get(i), "");
			System.out.print("]");
		}
		System.out.println("]");
		
		System.out.println("finished checking ArrayOfElementGroup\n");
	}

	private static void checkArrayOfElementField() throws Exception {
		System.out.println("checking ArrayOfElementField");
		System.out.println("checking basic array:");
		
		PrimeField prime = new PrimeField(BigInteger.valueOf(13));
		
		ArrayOfElementField arr = 
				new ArrayOfElementField(10, prime);
		
		for (int i = 0; i < arr.getMaxSize(); i++){
			arr.set(i, new ElementPrimeField(getRandNum(), prime));
		}
		
		System.out.print("[");
		for (int i = 0; i < arr.getMaxSize()-1; i++){
			System.out.print(arr.get(i).getElementValue()+", ");
		}
		System.out.println(arr.get(arr.getMaxSize()-1).getElementValue()+"]");
		
		try {
			arr.set(10, new ElementPrimeField(BigInteger.valueOf(12557), prime));
		} catch (Exception e) {
			System.out.println("Exception thrown correctly");
		}
		
		buildBasicArrayOfElementField(arr);
		
		System.out.println("\nchecking array of product field elements");
		
		
		Field[] fields = new PrimeField[2]; 
		fields[0] = prime;
		fields[1] = new PrimeField(BigInteger.valueOf(743));
		
		ElementField[] elemsfields = new ElementField[10];
		for (int i = 0; i < 5; i++){
			elemsfields[i] = new ElementPrimeField(getRandNum(), (PrimeField) fields[0]);
		}
		for (int i = 5; i < 10; i++){
			elemsfields[i] = new ElementPrimeField(getRandNum(), (PrimeField) fields[1]);
		}
		
		ProductField pfield = new ProductField(fields);
		
		ElementProductField[] pelems = new ElementProductField[5];
		for (int i = 0; i < pelems.length; i++){
			pelems[i] = new ElementProductField(pfield);
			pelems[i].set(0, elemsfields[i]);
			pelems[i].set(1, elemsfields[i+5]);
		}
		
		ArrayOfElementField parr = 
				new ArrayOfElementField(5, pfield);
		
		ArrayOfElementField parrc = 
			new ArrayOfElementField(5, pfield);
	
		for (int i = 0; i < parr.getMaxSize(); i++){
			parr.set(i, pelems[i]);
			parrc.set(i, pelems[i]);
		}
		
		System.out.print("[");
		for (int i = 0; i < parr.getMaxSize(); i++){
			printElementProductField(parr.get(i), "");
		}
		System.out.println("]");
		
		try {
			parr.set(10, new ElementProductField(pfield));
		} catch (Exception e) {
			System.out.println("Exception thrown correctly");
		}
		
		System.out.println("equals arrField expected true:"+(parr.equals(parrc)));
		System.out.println("equals arrField expected false:"+(arr.equals(parrc)));
		
		buildProductArrayOfElementField(parr);
		System.out.println("finished checking ArrayOfElementField\n\n");
	}

	private static void checkBigIntegerModulo() throws Exception {
		System.out.println("start of BigIntegerModulo");
		
		BigInteger e1, e2;
		
		BigIntegerModulo s = new BigIntegerModulo(BigInteger.valueOf(163));
		e1 = getRandNum(); e2 = getRandNum();
		System.out.println("add: "+e1+"+"+e2+"="+s.addModulo(e1, e2));
		e1 = getRandNum(); e2 = getRandNum();
		System.out.println("multiply: "+e1+"*"+e2+"="+s.multiplyModulo(e1, e2));
		System.out.println("subtract: 287874893-989809823098239089890="+s.subtractModulo(
				BigInteger.valueOf(287874893), new BigInteger("989809823098239089890")));
		e1 = getRandNum(); e2 = getRandNum();
		System.out.println("divide: "+e1+"/"+e2+"="+s.divideModulo(e1, e2));
		e1 = getRandNum(); e2 = getRandNum();
		System.out.println("addInverse: "+e1+"="+s.addInverseModulo(e1));
		System.out.println("multInverse: "+e2+"="+s.multInverseModulo(e2));
		e1 = getRandNum(); e2 = getRandNum();
		System.out.println("power: "+e1+"^"+e2+"="+s.powModulo(e1, e2));
		
		System.out.println("end of BigIntegerModulo\n\n");
	}

	private static BigInteger getRandNum() {
		return BigInteger.valueOf(Math.round(Math.random()*156238944)+1);
	}

	private static void checkPoint() throws Exception {
		System.out.println("Start of Point: ");
		Point p;
		try {
			p = new Point(new BigInteger("3902930429304"), new BigInteger("3902930955858555"));
			System.out.println("Point: ("+p.getX()+", "+p.getY()+")");
			p.setX(new BigInteger("4"));
			System.out.println("Point, x set to 4: ("+p.getX()+", "+p.getY()+")");
			p.setY(new BigInteger("29999999999999"));
			System.out.println("Point, y set to 29999999999999: ("+p.getX()+", "+p.getY()+")");
			try {
				p.setX(null);
			} catch (Exception e) {
				System.out.println("Exception thrown correctly");
			}
			System.out.println("Finished point\n\n");
		} catch (Exception e) {
			System.out.println("something went wrong");
			e.printStackTrace();
		}
	}
	
}
